package utils

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"io"
	"net"
	"reflect"
	"regexp"
	"runtime/debug"
	"sort"
	"strconv"
	"strings"
	"time"
	"unicode/utf16"
	"yungengxin2019/lwycommon/code/agent_code"
	"yungengxin2019/lwycommon/code/idcerrs"
	"yungengxin2019/lwycommon/entity/linux_entity/grpcproto/common"
)

const base_format = "2006-01-02 15:04:05"

// 生成md5
func Md5(buf []byte) string {
	hash := md5.New()
	hash.Write(buf)
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func CreateGuidString() string {
	b := make([]byte, 48)

	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}

	md5 := []byte(strings.ToUpper(Md5([]byte(base64.URLEncoding.EncodeToString(b)))))

	return string(md5[0:8]) + "-" + string(md5[8:12]) + "-" + string(md5[12:16]) + "-" + string(md5[16:20]) + "-" + string(md5[20:])
}

func CreateNetbarId() string {
	return "{" + CreateGuidString() + "}"
}

// 打印堆栈信息
func PrintStack() {
	beego.Error(string(debug.Stack()))
}

// 时间戳转日期格式
func TimeStampToTime(timestamp int64) time.Time {
	return time.Unix(timestamp, 0)
}

// IP(int) 转 字符串
func IpIntToString(ipInt int) string {
	ipSegs := make([]string, 4)
	var len int = len(ipSegs)
	buffer := bytes.NewBufferString("")
	for i := 0; i < len; i++ {
		tempInt := ipInt & 0xFF
		ipSegs[len-i-1] = strconv.Itoa(tempInt)
		ipInt = ipInt >> 8
	}
	for i := 0; i < len; i++ {
		buffer.WriteString(ipSegs[i])
		if i < len-1 {
			buffer.WriteString(".")
		}
	}
	return buffer.String()
}

func Ip2Long(ipstr string) (ip uint32) {
	r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})`
	reg, err := regexp.Compile(r)
	if err != nil {
		return
	}
	ips := reg.FindStringSubmatch(ipstr)
	if ips == nil {
		return
	}

	ip1, _ := strconv.Atoi(ips[1])
	ip2, _ := strconv.Atoi(ips[2])
	ip3, _ := strconv.Atoi(ips[3])
	ip4, _ := strconv.Atoi(ips[4])

	if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 {
		return
	}

	ip += uint32(ip1 * 0x1000000)
	ip += uint32(ip2 * 0x10000)
	ip += uint32(ip3 * 0x100)
	ip += uint32(ip4)

	return
}

func Long2Ip(ip uint32) string {
	return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24)
}

// 反转ip
func ReverseIp2Long(ip string) uint32 {

	// 反转ip
	tmp := strings.Split(ip, ".")
	if len(tmp) < 4 {
		return 0
	}
	tmp[0], tmp[3] = tmp[3], tmp[0]
	tmp[1], tmp[2] = tmp[2], tmp[1]
	ip = strings.Join(tmp, ".")

	// 转换ip
	return Ip2Long(ip)
}

// 反转ip
func ReverseLong2Ip(ipstr uint32) string {

	ip := Long2Ip(uint32(ipstr))

	// 反转ip
	tmp := strings.Split(ip, ".")
	if len(tmp) < 4 {
		return ""
	}
	tmp[0], tmp[3] = tmp[3], tmp[0]
	tmp[1], tmp[2] = tmp[2], tmp[1]
	ip = strings.Join(tmp, ".")

	return ip
}

func UTF16ToString(s []uint16) string {
	return string(utf16.Decode(s))
}

func UTF16ToStringDelLastChar(s []uint16) string {
	return UTF16ToString(s[:len(s)-1])
}

func StringToUTF16(s string) []uint16 {
	return utf16.Encode([]rune(s))
}

/*
 * @Author: hjd
 * @Description: []uint16 ->[]byte
 * @Date: 15:57 2020/10/14
 * @Param: 
 * @return: 
 **/
func Uint16sToBytes(array []uint16)[]byte {
	var destBytes []byte
	for _,v := range array{
		tansBytes := Uint16ToBytes(v)
		destBytes = append(destBytes,tansBytes...)
	}
	return destBytes
}

/*
 * @Author: hjd
 * @Description: uint16 -> []byte
 * @Date: 15:58 2020/10/14
 * @Param: 
 * @return: 
 **/
func Uint16ToBytes(n uint16) []byte {
	return []byte{
		byte(n),
		byte(n >> 8),
	}
}

// InArray判定 for Int
func InArrayInt(field int, arr []int) bool {
	for _, v := range arr {
		if v == field {
			return true
		}
	}

	return false
}

func InUint32Slice(field uint32, arr []uint32) bool {
	for _, v := range arr {
		if v == field {
			return true
		}
	}

	return false
}

func HttpBuildQuery(params map[string]string) string {
	var query []string
	for k, v := range params {
		query = append(query, k+"="+v)
	}

	if len(query) > 0 {
		return strings.Join(query, "&")
	}

	return ""
}

func DBColValueString(v interface{}) string {
	if value, ok := v.(string); ok {
		return value
	}

	beego.Error(fmt.Sprintf("v = %T， type error.", v))
	return ""
}

func DBColValueUint32(v interface{}) uint32 {
	str := DBColValueString(v)
	data, err := strconv.Atoi(str)
	if nil != err {
		beego.Error("failed to convert db col value to uint32.")
		return 0
	}

	return uint32(data)
}

// start：正数 - 在字符串的指定位置开始,超出字符串长度强制把start变为字符串长度
//       负数 - 在从字符串结尾的指定位置开始
//       0 - 在字符串中的第一个字符处开始
// length:正数 - 从 start 参数所在的位置返回
//       负数 - 从字符串末端返回

func Substr(str string, start, length int) string {
	if length == 0 {
		return ""
	}
	rune_str := []rune(str)
	len_str := len(rune_str)

	if start < 0 {
		start = len_str + start
	}
	if start > len_str {
		start = len_str
	}
	end := start + length
	if end > len_str {
		end = len_str
	}
	if length < 0 {
		end = len_str + length
	}
	if start > end {
		start, end = end, start
	}
	return string(rune_str[start:end])
}

func JsonPrintWithTab(v interface{}) string {
	result, _ := json.MarshalIndent(v, "", "\t")
	return fmt.Sprintf("%s", result)
}

func JsonPrint(v interface{}) string {
	result, _ := json.Marshal(v)
	return fmt.Sprintf("%s", result)
}

type lessFunc func(cond OrderCond, p1, p2 interface{}) bool
type sliceMultiFieldSort struct {
	conds []OrderCond
	data  []interface{}
	less  []lessFunc
}

// 排序的data参数的具体类型必须是指向切片的指针类型
func (ss *sliceMultiFieldSort) Sort(data interface{}) {
	if ss == nil {
		return
	}

	ss.data = ss.toInterfaceSlice(data)
	sort.Stable(ss)

	ss.setResultData(ss.data, 0, len(ss.data), data)
}

// 排序之后，返回执行页数据
// 排序的data参数的具体类型必须是指向切片的指针类型
func (ss *sliceMultiFieldSort) SortByPage(data interface{}, pageIndex, pageSize int32) error {
	dataType := reflect.TypeOf(data)
	if dataType.Kind() != reflect.Ptr || dataType.Elem().Kind() != reflect.Slice {
		return errSortParamMustBePointerToSlice
	}

	if ss == nil { // ss == nil // 不排序，只分页
		return ss.page(data, pageIndex, pageSize)
	}

	ss.data = ss.toInterfaceSlice(data)      // 保存数据
	if len(ss.data) == 0 || ss.data == nil { // 空数据，不做处理，直接返回
		return nil
	}

	sort.Stable(ss)

	return ss.page(data, pageIndex, pageSize)
}

func (ss *sliceMultiFieldSort) setResultData(in []interface{}, pageStart, pageEnd int, out interface{}) {
	elemNums := pageEnd - pageStart
	v := reflect.ValueOf(out)
	s := reflect.MakeSlice(v.Elem().Type(), 0, elemNums)
	for i := 0; i < elemNums; i++ {
		s = reflect.Append(s, reflect.ValueOf(in[pageStart+i]))
	}

	v.Elem().Set(s)
}

const allData = int32(-1)
const minPageIndex = int32(1)

func (ss *sliceMultiFieldSort) page(data interface{}, pageIndex, pageSize int32) error {
	if isEmptyData(data) {
		return nil // 空数据不分页
	}

	var d []interface{}
	if ss == nil { // 不排序，只分页
		d = ss.toInterfaceSlice(data)
	} else { // 对排序结果分页
		d = ss.data
	}

	if err := CheckPageIndexAndSize(pageIndex, pageSize); err != nil {
		return err
	}

	start := 0
	end := len(d)
	if pageSize > 0 {
		start = int(pageIndex-1) * int(pageSize)
		end = start + int(pageSize)

		if start >= len(d) {
			return idcerrs.New(agent_code.ErrPageStartPos)
		} else if end > len(d) {
			end = len(d)
		}
	}

	if end <= start {
		return idcerrs.New(agent_code.ErrPageParam)
	}

	ss.setResultData(d, start, end, data)

	return nil
}

func (ss *sliceMultiFieldSort) toInterfaceSlice(data interface{}) []interface{} {
	if isEmptyData(data) {
		return nil // 空数据不处理
	}

	dataType := reflect.TypeOf(data)
	if dataType.Kind() != reflect.Ptr {
		panic(fmt.Sprintf("concrete type of param data must pointer to slice: %s", dataType.Name()))
	}

	if dataType.Elem().Kind() != reflect.Slice {
		panic(fmt.Sprintf("type that data pointer to  must a slice: %s", dataType.Elem().Name()))
	}

	v := reflect.ValueOf(data).Elem()
	if v.IsNil() {
		panic(fmt.Sprintf("type that data pointer to must not a nil pointer to slice"))
	}

	var d []interface{}
	n := v.Len()
	for i := 0; i < n; i++ {
		d = append(d, v.Index(i).Interface())
	}

	return d
}

func (ss *sliceMultiFieldSort) Len() int {
	return len(ss.data)
}

func (ss *sliceMultiFieldSort) Swap(i, j int) {
	ss.data[i], ss.data[j] = ss.data[j], ss.data[i]
}

func (ss *sliceMultiFieldSort) Less(i, j int) bool {
	p, q := ss.data[i], ss.data[j]
	var k int
	for k = 0; k < len(ss.less); k++ {
		less := ss.less[k]
		switch {
		case less(ss.conds[k], p, q):
			return true
		case less(ss.conds[k], q, p):
			return false
		}
	}

	return true // 相等，保持原来顺序不变
}

func OrderSliceByPage(data interface{}, cond *common.OrderCond, defOrderCond OrderCond, pageIndex, pageSize int32) error {
	return SliceOrderedBy(NewOrderCond(cond, defOrderCond)).SortByPage(data, pageIndex, pageSize)
}

func SliceOrderedBy(conds ...OrderCond) *sliceMultiFieldSort {
	if len(conds) == 0 { // 一个字段没有，不排序
		return nil
	}

	var s sliceMultiFieldSort
	s.conds = append(s.conds, conds...)

	mySortFunc := func(cond OrderCond, p1, p2 interface{}) bool {
		return cond.compareValue(getFieldValue(cond, p1, p2))
	}

	var sortFunc []lessFunc
	for _, cond := range conds {
		var f lessFunc
		if cond.F != nil {
			f = func(cond OrderCond, p1, p2 interface{}) bool {
				value1, value2 := getFieldValue(cond, p1, p2)
				return cond.compareValue(cond.F(value1, value2)) // 用户指定排序算法
			}
		} else {
			f = mySortFunc
		}

		sortFunc = append(sortFunc, f)
	}

	s.less = sortFunc

	return &s
}

func isEmptyData(data interface{}) bool {
	if data == nil {
		return true // 空数据不执行任何操作
	}

	v := reflect.ValueOf(data).Elem()
	if v.IsNil() {
		return true // 空数据不执行任何操作
	}

	return false
}

func SortByPage(data interface{}, pageIndex uint64, pageSize int64, userOrderCond *OrderCond, defOrderFields ...OrderCond) error {
	if isEmptyData(data) {
		return nil // 空数据不排序
	}

	var cond []OrderCond
	// 按照默认字段排序
	if ((userOrderCond == nil) || len(userOrderCond.Field) == 0) && len(defOrderFields) != 0 {
		for _, c := range defOrderFields {
			if len(c.Field) == 0 {
				panic("排序的默认字段名不能够为空")
			}

			cond = append(cond, c)
		}

		if len(cond) != 0 {
			logs.Debug("按照默认字段分页排序：pageIndex=%d，pageSize=%d，%s", pageIndex, pageSize, JsonPrintWithTab(cond))
		} else {
			logs.Debug("无排序字段，无默认字段排序，只分页：pageIndex=%d，pageSize=%d", pageIndex, pageSize)
		}
	} else if userOrderCond != nil && len(userOrderCond.Field) != 0 { // 用户指定字段排序
		var c OrderCond
		c.Field = userOrderCond.Field
		c.Type = OrderType(userOrderCond.Type)
		if c.Type == Not { // 不排序，默认用升序排序
			c.Type = Asc
		}
		c.F = userOrderCond.F
		cond = append(cond, c)
		logs.Debug("按照用户指定字段排序：c.Field=%s，c.Type=%d，pageIndex=%d，pageSize=%d，userOrderCond.Field=%s，userOrderCond.Type=%d，%s",
			c.Field, c.Type, pageIndex, pageSize, userOrderCond.Field, userOrderCond.Type, JsonPrintWithTab(cond))
	} else { // 无排序字段，只是分页
		logs.Debug("无排序字段，只分页：pageIndex=%d，pageSize=%d", pageIndex, pageSize)
	}

	return SliceOrderedBy(cond...).SortByPage(data, int32(pageIndex), int32(pageSize))
}

func getFieldValue(cond OrderCond, p1, p2 interface{}) (interface{}, interface{}) {
	if p1 == nil || p2 == nil {
		logs.Debug("sort param: p1 == nil，p2 == nil")
		return nil, nil
	}

	if len(cond.Field) == 0 {
		logs.Debug("sort field name is empty")
		return nil, nil
	}

	var value1 reflect.Value
	var value2 reflect.Value
	t1 := reflect.TypeOf(p1)
	if t1.Kind() == reflect.Struct {
		value1 = reflect.ValueOf(p1)
		value2 = reflect.ValueOf(p2)
	} else if t1.Kind() == reflect.Ptr && t1.Elem().Kind() == reflect.Struct {
		value1 = reflect.ValueOf(p1).Elem()
		value2 = reflect.ValueOf(p2).Elem()
	} else {
		logs.Error("sort param type error: <p1, p2 type: %s>", t1.String())
		return nil, nil
	}

	fieldNames := strings.Split(cond.Field, ".")
	switch v1 := value1.FieldByName(fieldNames[0]); v1.Kind() {
	case reflect.String:
		return v1.String(), value2.FieldByName(fieldNames[0]).String()
	case reflect.Int8:
		return int8(v1.Int()), int8(value2.FieldByName(fieldNames[0]).Int())
	case reflect.Int16:
		return int16(v1.Int()), int16(value2.FieldByName(fieldNames[0]).Int())
	case reflect.Int32:
		return int32(v1.Int()), int32(value2.FieldByName(fieldNames[0]).Int())
	case reflect.Int64:
		return int64(v1.Int()), int64(value2.FieldByName(fieldNames[0]).Int())
	case reflect.Int:
		return v1.Int(), value2.FieldByName(fieldNames[0]).Int()
	case reflect.Uint8:
		return uint8(v1.Uint()), uint8(value2.FieldByName(fieldNames[0]).Uint())
	case reflect.Uint16:
		return uint16(v1.Uint()), uint16(value2.FieldByName(fieldNames[0]).Uint())
	case reflect.Uint32:
		return uint32(v1.Uint()), uint32(value2.FieldByName(fieldNames[0]).Uint())
	case reflect.Uint64:
		return uint64(v1.Uint()), uint64(value2.FieldByName(fieldNames[0]).Uint())
	case reflect.Uint:
		return v1.Uint(), value2.FieldByName(fieldNames[0]).Uint()
	case reflect.Struct: // 结构体类型，只支持对时间的排序
		if time1, ok := v1.Interface().(time.Time); ok {
			time2, _ := value2.FieldByName(fieldNames[0]).Interface().(time.Time)
			return time1.UnixNano(), time2.UnixNano()
		}

		if v1.CanInterface() {
			c := OrderCond{Field: strings.Join(fieldNames[1:], "."), Type: cond.Type, F: cond.F}
			v2 := value2.FieldByName(fieldNames[0])
			return getFieldValue(c, v1.Interface(), v2.Interface())
		}

		logs.Error("unsupported field type sort: %s, field type=%s", fieldNames[0], reflect.TypeOf(v1).Name())
		return nil, nil
	case reflect.Ptr:
		if v1.Elem().Kind() == reflect.Struct && v1.Elem().CanInterface() {
			c := OrderCond{Field: strings.Join(fieldNames[1:], "."), Type: cond.Type, F: cond.F}
			v2 := value2.FieldByName(fieldNames[0])
			return getFieldValue(c, v1.Elem().Interface(), v2.Elem().Interface())
		}
		return nil, nil
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		return v1.Float(), value2.FieldByName(fieldNames[0]).Float()

	case reflect.Invalid:
		// totalFiledNums := value1.NumField()
		// for i := 0; i < totalFiledNums; i++ { // 遍历结构的所有结构体成员查找字段
		//	if fv1 := value1.Field(i); fv1.Type().Kind() == reflect.Struct {
		//		v1, v2 := getFieldValue(cond, fv1, value2.Field(i))
		//		if v1 == nil || v2 == nil { // 没有找到排序字段，查找结构体下一个成员
		//			continue
		//		}
		//		return v1, v2
		//	} else if fv1.Type().Kind() == reflect.Ptr && fv1.Type().Elem().Kind() == reflect.Struct {
		//		fv1 = fv1.Elem()
		//		fv2 := value2.Field(i).Elem()
		//		if !fv1.CanInterface() {
		//			continue // 排除非导出字段导致的崩溃
		//		}
		//		v1, v2 := getFieldValue(cond, fv1.Interface(), fv2.Interface())
		//		if v1 == nil || v2 == nil { // 没有找到排序字段，查找结构体下一个成员
		//			continue
		//		}
		//		return v1, v2
		//	}
		// }

		logs.Debug("sort field is not exist: %s", fieldNames[0])
		return nil, nil

	default:
		logs.Debug("exception that get sort field value: field=%s，value=%v，type=%s", fieldNames[0], v1, reflect.TypeOf(v1).Kind().String())
		return nil, nil
	}
}

type OrderType int

const (
	Not OrderType = iota
	Asc
	Desc
)

const NotPage = -1

func NewOrderCond(cond *common.OrderCond, defOrderCond OrderCond) OrderCond {
	var orderCond OrderCond
	if cond != nil {
		orderCond = OrderCond{Field: cond.Field, Type:  OrderType(cond.Type), F: nil}
	} else if cond == nil || len(cond.Field) == 0 { // 没有指定排序字段
		orderCond = OrderCond{Field: defOrderCond.Field, Type:  defOrderCond.Type, F: nil}
	}

	return orderCond
}

// v1：记录1对应的字段值
// v2：记录2对应的字段值
type fieldValueTransFunc func(v1, v2 interface{}) (interface{}, interface{})
type OrderCond struct {
	Field string              // 排序字段名
	Type  OrderType           // 排序顺序
	F     fieldValueTransFunc // 排序字段比较函数，为空，使用默认值比较
}

func (c *OrderCond) strCompare(v1, v2 string) bool {
	if c.Type == Asc || c.Type == Not {
		return v1 < v2
	} else {
		return v2 < v1
	}
}

func (c *OrderCond) uint64Compare(v1, v2 uint64) bool {
	if c.Type == Asc || c.Type == Not {
		return v1 < v2
	} else {
		return v2 < v1
	}
}

func (c *OrderCond) int64Compare(v1, v2 int64) bool {
	if c.Type == Asc || c.Type == Not {
		return v1 < v2
	} else {
		return v2 < v1
	}
}

func (c *OrderCond) float32Compare(v1, v2 float32) bool {
	if c.Type == Asc || c.Type == Not {
		return v1 < v2
	} else {
		return v2 < v1
	}
}

func (c *OrderCond) float64Compare(v1, v2 float64) bool {
	if c.Type == Asc || c.Type == Not {
		return v1 < v2
	} else {
		return v2 < v1
	}
}

func (c *OrderCond) compareValue(value1, value2 interface{}) bool {
	if value1 == nil || value2 == nil {
		logs.Debug("value1 == nil || value2 == nil, not sort")
		return true // 返回true维持原值顺序不变
	}

	switch v1 := value1.(type) {
	case string:
		v2, _ := value2.(string)
		return c.strCompare(v1, v2)
	case int8:
		v2 := value2.(int8)
		return c.int64Compare(int64(v1), int64(v2))
	case int16:
		v2 := value2.(int16)
		return c.int64Compare(int64(v1), int64(v2))
	case int32:
		v2 := value2.(int32)
		return c.int64Compare(int64(v1), int64(v2))
	case int64:
		v2 := value2.(int64)
		return c.int64Compare(int64(v1), int64(v2))
	case int:
		v2 := value2.(int)
		return c.int64Compare(int64(v1), int64(v2))
	case uint8:
		v2 := value2.(uint8)
		return c.uint64Compare(uint64(v1), uint64(v2))
	case uint16:
		v2 := value2.(uint16)
		return c.uint64Compare(uint64(v1), uint64(v2))
	case uint32:
		v2, _ := value2.(uint32)
		return c.uint64Compare(uint64(v1), uint64(v2))
	case uint64:
		v2, _ := value2.(uint64)
		return c.uint64Compare(v1, v2)
	case uint:
		v2, _ := value2.(uint)
		return c.uint64Compare(uint64(v1), uint64(v2))
	case float32:
		v2, _ := value2.(float32)
		return c.float32Compare(float32(v1), float32(v2))
	case float64:
		v2, _ := value2.(float64)
		return c.float64Compare(float64(v1), float64(v2))

	default:
		logs.Debug("field value type error, unkown type: value1=%v, value2=%v, cond=%s", value1, value2, JsonPrint(c))
		return true // 返回true维持原值顺序不变
	}
}

func CheckPageIndexAndSize(pageIndex, pageSize int32) error {
	if pageSize == 0 {
		return idcerrs.New(agent_code.ErrPageSizeEqualZero)
	}

	if pageSize < allData {
		return idcerrs.New(agent_code.ErrPageSize)
	}

	if pageSize != allData && pageIndex < minPageIndex {
		return idcerrs.New(agent_code.ErrPageIndex)
	}

	return nil
}

// 获取本地IP(获取多个IP)
func GetLocalIps() []string {

	var ips []string
	netInterfaces, err := net.Interfaces()
	if err != nil {
		return ips
	}

	for i := 0; i < len(netInterfaces); i++ {

		// 网卡状态要为:up
		if 0 == (netInterfaces[i].Flags & net.FlagUp) {
			continue
		}

		// Filter linux invalid network card
		if strings.Contains(netInterfaces[i].Name, "lo") ||
			strings.Contains(netInterfaces[i].Name, "docker") ||
			strings.Contains(netInterfaces[i].Name, "veth") {
			continue
		}

		// Filter windows invalid network card
		if strings.Contains(netInterfaces[i].Name, "SSTAP") ||
			strings.Contains(netInterfaces[i].Name, "VMware") {
			continue
		}

		// 虚拟网桥(在VMware 虚拟机上默认安装这个网卡)
		if strings.Contains(netInterfaces[i].Name, "virbr") {
			continue
		}

		addrs, _ := netInterfaces[i].Addrs()

		for _, address := range addrs {

			ipnet, ok := address.(*net.IPNet)
			if !ok {
				continue
			}

			if ipnet.IP.IsLoopback() ||
				ipnet.IP.IsUnspecified() {
				continue
			}

			if nil == ipnet.IP.To4() {
				continue
			}

			ips = append(ips, ipnet.IP.String())
		}
	}

	return ips
}

var (
	errSortParamMustBePointerToSlice = idcerrs.New(agent_code.ErrSortParamMustBePointerToSlice)
)
